﻿Imports System
Imports System.Drawing
Imports System.Text
Imports System.Runtime.InteropServices

Public Class CIndicator
    Implements IDisposable

    <DllImport("USER32.DLL", CharSet:=CharSet.Auto)>
    Private Shared Function DestroyIcon(ByVal handle As IntPtr) As Boolean
    End Function

    Private _icon As New NotifyIcon
    Private _tmr As New Timer
    Private _read(1) As PerformanceCounter
    Private _write(1) As PerformanceCounter
    Private _letter(1) As String
    Private _bmp As Bitmap = New Bitmap(16, 16)
    Private _g As Graphics = Graphics.FromImage(_bmp)
    Private _skin As CSkin
    Private _drivesNum As Integer
    Private _brush As SolidBrush
    Private _tip(1) As String

    Public Sub New(ByVal drives() As String, ByVal skin As CSkin)
        _drivesNum = UBound(drives)
        If _drivesNum < 0 Then Return

        _skin = skin

        For i As Integer = 0 To _drivesNum
            _read(i) = New PerformanceCounter("LogicalDisk", "Disk Read Bytes/sec", drives(i))
            _write(i) = New PerformanceCounter("LogicalDisk", "Disk Write Bytes/sec", drives(i))
            _letter(i) = drives(i).TrimEnd(":")
        Next

        AddHandler _tmr.Tick, AddressOf Tick
        AddHandler _icon.MouseDoubleClick, AddressOf Form1.cmsRestore_Click

        _tmr.Interval = My.Settings.Interval

        _g.TextRenderingHint = _skin.RenderingHint
        _icon.ContextMenuStrip = Form1.cms
        _icon.Visible = True
        _icon.Text = "Logical Disk Indicator"
        _icon.Icon = Icon.FromHandle(_bmp.GetHicon()) '// Dummy

        _tmr.Enabled = True
    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose
        _tmr.Dispose()
        For i As Integer = 0 To _drivesNum
            _read(i).Dispose()
            _write(i).Dispose()
        Next
        DestroyIcon(_icon.Icon.Handle)
        _icon.Dispose()
        _bmp.Dispose()
    End Sub

    Private Sub Tick()
        DestroyIcon(_icon.Icon.Handle)

        For i As Integer = 0 To _drivesNum
            Dim _r = _read(i).NextValue
            Dim _w = _write(i).NextValue

            _g.DrawImage(_skin.Drives(i).Image(If(_w > 0, 1, 0) * 2 + If(_r > 0, 1, 0)), _skin.Drives(i).ImageRect)

            If _skin.DriveLetter Then
                _g.DrawString(_letter(i), _skin.Drives(i).Font, _skin.Drives(i).Brush, _skin.Drives(i).FontRect)
            End If

            If My.Settings.ToolTip Then
                _tip(i) = _letter(i) & ": " & Units(_r) & " / " & Units(_w)
            End If

            If Form1.WindowState = FormWindowState.Normal Then
                Form1.lsvDrive.Items(_letter(i)).SubItems(1).Text = Units(_r)
                Form1.lsvDrive.Items(_letter(i)).SubItems(2).Text = Units(_w)
            End If
        Next

        If My.Settings.ToolTip Then
            _icon.Text = _tip(0) & vbCrLf & _tip(1)
        End If

        _icon.Icon = Icon.FromHandle(_bmp.GetHicon())
    End Sub

    Private Const Ki = 1024
    Private Const Mi = 1024 * 1024
    Private Const Gi = 1024 * 1024 * 1024

    Private Function Units(ByVal v As Single) As String
        If v > Gi Then
            Return String.Format("{0:#,0} GB ", Math.Ceiling(v / Gi))
        ElseIf v > Mi Then
            Return String.Format("{0:#,0} MB ", Math.Ceiling(v / Mi))
        ElseIf v > Ki Then
            Return String.Format("{0:#,0} KB ", Math.Ceiling(v / Ki))
        Else
            Return String.Format("{0:#,0} B ", v)
        End If
    End Function

End Class
